grammar Cmm;
import CmmLex;

program: stmt+;

stmt    : declStmt
        | ifStmt
        | whileStmt
        |(assignStmt SEMI)
        | writeStmt
        | readStmt
        | stmtBlock
        | forStmt
        ;

declStmt: type deAs(COMMA deAs)* SEMI       #declStmt1
        | type L_BRACKET INT R_BRACKET ID SEMI  #declStmt2
        ;

deAs: ID                #deAs1
    | ID ASSIGN expr        #deAs2
    | ID ASSIGN MINUS expr  #deAs3
    ;

ifStmt  : IF L_PAREN compare R_PAREN stmtBlock elseIfStmt*
        | IF L_PAREN compare R_PAREN stmtBlock elseIfStmt* elseStmt
        ;

elseIfStmt  : ELSE_IF L_PAREN compare R_PAREN stmtBlock;

elseStmt    : ELSE stmtBlock;

whileStmt: WHILE L_PAREN compare R_PAREN stmtBlock;

assignStmt: variable ASSIGN expr  #assignStmt1
          | variable ASSIGN MINUS expr #assignStmt2
          ;

writeStmt: WRITE L_PAREN expr R_PAREN SEMI;

readStmt: READ L_PAREN variable R_PAREN SEMI;

stmtBlock: L_BRACE stmt* R_BRACE;

forStmt : FOR L_PAREN assignStmt SEMI compare SEMI assignStmt R_PAREN stmtBlock #forStmt1
        | FOR L_PAREN declStmt compare SEMI assignStmt R_PAREN stmtBlock    #forStmt2
        ;

type: T_INT  #type1
    | T_DOUBLE #type2
    |T_BOOL #type3
    ;

variable: ID                #variable1
        | ID L_BRACKET expr R_BRACKET #variable2
        ;

constant: INT| DOUBLE ;

compare : LOG_NOT compare       #compare1
        | expr op=(BIGGER_THAN|LESS_THAN|NO_LESS|NO_MORE|EQUAL|UN_EQUAL) expr   #compare2
        | expr #compare3
        //| L_PAREN compare R_PAREN
        ;


expr    : expr op=(MUL|DIV|MOD) expr        #mulExpr1
        | expr op=(PLUS|MINUS) expr         #expr1
        | variable      #factor1
        | constant      #factor2
        | L_PAREN expr R_PAREN      #factor3
        | L_PAREN MINUS expr R_PAREN        #factor4
        ;